java线程池相关概念

线程池

关于参数的描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
  1. corePoolSize 线程的核心线程数,核心线程是会保持在线程池中,即使核心线程处于空闲状态,除非allowCoreThreadTimeOut被设置。
  2. maximumPoolSize: 指的是线程池中允许的最大的线程数
  3. keepAliveTime: 当线程数大于核心线程数时,多余的空闲线程等待任务的超时时间为keepAliveTime,超时后空闲线程将会被终止
  4. unit: keepAliveTime的时间单位
  5. workQueue:线程池的任务队列,这个队列是阻塞式队列,任务通过execute提交。
  6. threadFactor: 用于创建线程池中线程的工厂类
  7. handler:饱和策略

线程池任务处理过程

当通过execute提交新任务到线程池中,线程池会做如下操作:

  1. 如果线程池中正在运行的线程小于corePoolSize,则创建一个新的线程来执行任务。否则,执行步骤2
  2. 判断线程工作队列workQueue是否已经满,如果工作队列没有满,则将新提交的任务存储在工作队列中等待。否则执行步骤3
  3. 判断线程池中正在运行的线程数是否小于maximumPoolSize,如果小于,则创建线程运行这个任务,否则执行步骤4
  4. 这时候线程池的工作队列已满,正在运行的线程数已达到maximumPoolSize指定的值,该任务交给饱和策略处理。

当创建的线程处于空闲状态时,如果超过keepAliveTime的时间,线程池会判断当前运行的线程是否大于coorPoolSize,如果是,那么线程被终止掉。所有线程池的任务完成后,它最终会收缩到coorPoolSize的大小。

这个过程说明,并不是先加入任务就一定会先执行。假设队列大小为 4,corePoolSize为2,maximumPoolSize为6,那么当加入15个任务时,执行的顺序类似这样:首先执行任务 1、2,然后任务3~6被放入队列。这时候队列满了,任务7、8、9、10 会被马上执行,而任务 11~15 则会抛出异常。最终顺序是:1、2、7、8、9、10、3、4、5、6。当然这个过程是针对指定大小的ArrayBlockingQueue来说,如果是LinkedBlockingQueue,因为该队列无大小限制,所以不存在上述问题

常用线程池

Java通过Executors提供四种线程池,分别为:

  1. newCachedThreadPool()
1
2
3
4
5
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}

创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒处于等待任务到来)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池的最大值是Integer的最大值(2^31-1)。

  1. newFixedThreadPool(nThreads)
1
2
3
4
5
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}

创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,在提交新任务,任务将会进入等待队列中等待。如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

  1. newSingleThreadExecutor
1
2
3
4
5
6
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}

创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

  1. newScheduledThreadPool(int corePoolSize)
1
2
3
4
5
6
7
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
new DelayedWorkQueue());
}

创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

坚持原创技术分享,您的支持将鼓励我继续创作!